﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum EPlayerType
{
    P1,
    P2,
}
public enum EPlayerState
{
    Normal,
    Stretching,
    Crouching,
}
public class Player : MonoBehaviour
{
    public EPlayerType PlayerType;
    public SpriteRenderer MySprite;
    public SpriteRenderer MouthSprite;
    public Rigidbody2D MyRigidBody;
    public CapsuleCollider2D MyCollider;
    public GameObject MouthPosition;
    public Animator MyAnimator;

    private const float NormalHeight = 1.5f;
    private const float StretchHeight = 2.5f;
    private const float CrouchHeight = 1.3f;
    private const float AddForce = 8f;
    private const float TextAddForce = 6f;
    private const float MaxVelocity = 5f;
    private const float JumpForce = 250f;
    private const float UpStateBlendTime = 1.2f;
    private const float DownStateBlendTime = 0.5f;
    private static float[] HeightArray = new float[] { NormalHeight, StretchHeight, CrouchHeight };
    private const float ColliderXScale = 0.84f / NormalHeight;
    private const float ColliderYScale = 1.35f / NormalHeight;
    private const float PlayerHeadOffset = 0.25f;

    private KeyCode mUpKeyCode;
    private KeyCode mDownKeyCode;
    private KeyCode mLeftKeyCode;
    private KeyCode mRightKeyCode;
    private KeyCode mJumpKeyCode;
    private EPlayerState mCurrentState;
    private EPlayerState mLastState;
    private float mChangeStateTime;
    private float mInAirTime;
    private float mLastJumpTime;

    private string HoriAxis;
    private string VertiAxis;
    private string JumpAxis;
    private string JumpSoundeName;
    public bool OnlyCanCrouch
    {
        get;
        set;
    }
    void Start ()
    {
		if (PlayerType == EPlayerType.P1)
        {
            mUpKeyCode = KeyCode.W;
            mDownKeyCode = KeyCode.S;
            mLeftKeyCode = KeyCode.A;
            mRightKeyCode = KeyCode.D;
            mJumpKeyCode = KeyCode.C;
            HoriAxis = "Horizontal";
            VertiAxis = "Vertical";
            JumpAxis = "Jump1";
            JumpSoundeName = "JumpSound1";
        }
        else if (PlayerType == EPlayerType.P2)
        {
            mUpKeyCode = KeyCode.I;
            mDownKeyCode = KeyCode.K;
            mLeftKeyCode = KeyCode.J;
            mRightKeyCode = KeyCode.L;
            mJumpKeyCode = KeyCode.N;
            HoriAxis = "Horizontal2";
            VertiAxis = "Vertical2";
            JumpAxis = "Jump2";
            JumpSoundeName = "JumpSound2";
        }
        mCurrentState = EPlayerState.Normal;
    }
	
	void Update ()
    {
        if ((Input.GetKey(mRightKeyCode) || Input.GetAxis(HoriAxis) > 0) && !OnlyCanCrouch)
        {
            if (MyRigidBody.velocity.x < MaxVelocity)
            {
                MyRigidBody.AddForce(Vector2.right * AddForce);
            }
            GameManager.GetInstance().AddTextForce(Vector2.right * TextAddForce, MyRigidBody.velocity);
        }
        else if ((Input.GetKey(mLeftKeyCode) || Input.GetAxis(HoriAxis) < 0) && !OnlyCanCrouch)
        {
            if (MyRigidBody.velocity.x > -MaxVelocity)
            {
                MyRigidBody.AddForce(Vector2.left * AddForce);
            }
            GameManager.GetInstance().AddTextForce(Vector2.left * TextAddForce, MyRigidBody.velocity);
        }
        bool isGrounded = MyRigidBody.IsTouchingLayers(1 << PhysicsLayer.Floor);
        if (!isGrounded)
        {
            mInAirTime += Time.deltaTime;
        }
        else
        {
            mInAirTime = 0f;
        }
        if ((Input.GetKey(mJumpKeyCode) || Input.GetAxis(JumpAxis) > 0) && !OnlyCanCrouch)
        {
            if (isGrounded && Time.time - mLastJumpTime > 0.6f)
            {
                MyRigidBody.AddForce(Vector2.up * JumpForce);
                GameObject.Find(JumpSoundeName).GetComponent<AudioSource>().Play();
                mLastJumpTime = Time.time;
            }
        }
        MyAnimator.SetBool("IsGrounded", isGrounded);
        MyAnimator.SetFloat("InAirTime", mInAirTime);
        if (MyRigidBody.velocity.x >= 0 ^ PlayerType == EPlayerType.P2)
        {
            MySprite.flipX = false;
            MouthSprite.flipX = false;
        }
        else
        {
            MySprite.flipX = true;
            MouthSprite.flipX = true;
        }
        if ((Input.GetKey(mUpKeyCode) || Input.GetAxis(VertiAxis) > 0) && !OnlyCanCrouch)
        {
            ChangeState(EPlayerState.Stretching);
        }
        else if ((Input.GetKey(mDownKeyCode) || Input.GetAxis(VertiAxis) < 0))
        {
            ChangeState(EPlayerState.Crouching);
        }
        else
        {
            ChangeState(EPlayerState.Normal);
        }
    }
    private void ChangeState(EPlayerState newState)
    {
        if (newState != mCurrentState)
        {
            mLastState = mCurrentState;
            mCurrentState = newState;
            mChangeStateTime = Time.time;
        }
    }
    private void FixedUpdate()
    {
        if (mCurrentState == EPlayerState.Stretching)
        {
            if (Time.time - mChangeStateTime <= UpStateBlendTime)
            {
                float percent = (Time.time - mChangeStateTime) / UpStateBlendTime;
                float height = Mathf.Lerp(MySprite.size.y, HeightArray[(int)mCurrentState], percent);
                Vector2 size = MySprite.size;
                size.y = height;
                MySprite.size = size;
                MyCollider.size = new Vector2(size.x * ColliderXScale, size.y * ColliderYScale);

                float deltaHeight = height - NormalHeight;
                Vector3 mouthPosition = MouthPosition.transform.localPosition;
                mouthPosition.y = deltaHeight - (height / 2f) + NormalHeight / 2f;
                MouthPosition.transform.localPosition = mouthPosition;
            }
        }
        else
        {
            if (Time.time - mChangeStateTime <= DownStateBlendTime)
            {
                float percent = (Time.time - mChangeStateTime) / DownStateBlendTime;
                float height = Mathf.Lerp(MySprite.size.y, HeightArray[(int)mCurrentState], percent);
                Vector2 size = MySprite.size;
                size.y = height;
                MySprite.size = size;
                MyCollider.size = new Vector2(size.x * ColliderXScale, size.y * ColliderYScale);

                float deltaHeight = height - NormalHeight;
                Vector3 mouthPosition = MouthPosition.transform.localPosition;
                mouthPosition.y = deltaHeight - (height / 2f) + NormalHeight / 2f;
                MouthPosition.transform.localPosition = mouthPosition;
            }
        }
    }
    public Vector3 GetHeadPosition()
    {
        return transform.position + Vector3.up * (MySprite.size.y / 2f * transform.localScale.x + PlayerHeadOffset);
    }
    public EPlayerState GetState()
    {
        return mCurrentState;
    }
}
